﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using KylinORM.Utils;
using KylinORM.Aspect;

namespace KylinORM.Aspect.Definition
{
    /// <summary>
    /// 实体类型的字段描述
    /// </summary>
    internal class EntityDefinition : ICloneable<EntityDefinition>
    {
        private EntityDefinition()
        {
        }

        /// <summary>
        /// 使用反射获取字段描述
        /// </summary>
        /// <param name="entityType">实体类型</param>
        /// <param name="definitionRule">实体映射规则</param>
        internal EntityDefinition(Type entityType, IEntityDefinitionRule definitionRule)
        {
            //实体属性
            EntityInfo = definitionRule.GetEntityDefinition(entityType);
            loadAttributeSettings(entityType, EntityInfo);
            //实体字段属性
            List<KeyValuePair<string, EntityFieldInfo>> fields = new List<KeyValuePair<string, EntityFieldInfo>>();
            foreach (PropertyInfo prop in entityType.GetProperties())
            {
                if (!TypeConverter.IsValueType(prop.PropertyType))
                    continue;

                EntityFieldInfo field = definitionRule.GetEntityFieldDefinition(prop);
                loadAttributeSettings(prop, field);

                if (field.IsIgnoredField != true)
                    fields.Add(new KeyValuePair<string, EntityFieldInfo>(prop.Name, field));
            }
            EntityFieldInfos = new ReadonlyOrderedDictionary<EntityFieldInfo>(fields);
        }

        #region 加载实体和字段属性
        /// <summary>
        /// 读取实体的特性设置
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="entity"></param>
        private void loadAttributeSettings(Type entityType, EntityInfo entity)
        {
            //从特性分析表名
            foreach (EntityAttribute attr in entityType.GetCustomAttributes(typeof(EntityAttribute), true))
            {
                if (!string.IsNullOrEmpty(attr.TableName))
                    entity.TableName = attr.TableName;
                if (attr.JoinMethod != null)
                    entity.JoinMethod = attr.JoinMethod;
                if (!string.IsNullOrEmpty(attr.JoinTarget))
                    entity.JoinTarget = attr.JoinTarget;
            }
        }

        /// <summary>
        /// 读取实体的特性设置
        /// </summary>
        /// <param name="prop">实体属性</param>
        /// <param name="field">实体属性描述</param>
        private void loadAttributeSettings(PropertyInfo prop, EntityFieldInfo field)
        {
            foreach (EntityFieldAttribute attr in prop.GetCustomAttributes(typeof(EntityFieldAttribute), true))
            {
                if (!string.IsNullOrEmpty(attr.TableName))
                    field.TableName = attr.TableName;
                if (!string.IsNullOrEmpty(attr.FieldName))
                    field.FieldName = attr.FieldName;
                if (attr.SelectMethod != null)
                    field.SelectMethod = attr.SelectMethod;

                if (attr.IsIgnoredField != null)
                    field.IsIgnoredField = attr.IsIgnoredField;
                if (attr.IsPrimaryField != null)
                    field.IsPrimaryField = attr.IsPrimaryField;
                if (attr.IsIdentityField != null)
                    field.IsIdentityField = attr.IsIdentityField;
            }
        }
        #endregion

        /// <summary>
        /// 目标实体的名称
        /// </summary>
        internal EntityInfo EntityInfo { get; private set; }
        /// <summary>
        /// 目标实体的属性列表
        /// </summary>
        internal ReadonlyOrderedDictionary<EntityFieldInfo> EntityFieldInfos { get; private set; }
        
        EntityDefinition ICloneable<EntityDefinition>.Clone()
        {
            return new EntityDefinition
            {
                EntityInfo = ((ICloneable<EntityInfo>)this.EntityInfo).Clone(),
                EntityFieldInfos = ((ICloneable<ReadonlyOrderedDictionary<EntityFieldInfo>>)this.EntityFieldInfos).Clone()
            };
        }

        object ICloneable.Clone()
        {
            return ((ICloneable<EntityDefinition>)this).Clone();
        }
    }
}
